﻿/****************************************************************************
Copyright (c) 2014-2015 凌惊雪 微信:Lingjingxue 邮箱:lingjingxue@sina.com QQ:271487457

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

using UtilLib;
using UtilPublic.Mysql;
using UtilPublic.ServerLoger;
using UtilPublic.Timer;
using ServerGame.Manager;
using System;
using ServerBase.Config;
using ServerBase.Service;
using ServerBase.Other;
using ServerBase.IniFile;
using System.Collections.Generic;
using ServerPublic.Data;
using static ServerPublic.Data.PubDataServerMgr;
using UtilPublic.ApiDispatcher;
using ServerBase.LunarSocket;

namespace ServerGame.Service
{
    /// <summary>
    /// 服务器心跳
    /// </summary>
    public static partial class LoopServer
    {
        #region 注册
        public static void LoopServerRegister()
        {
            ListMillisecond.TryAdd(ServerTimer.LoopMillisecond);


            //ListSecond
            ListSecond.TryAdd(ApiDpCmdMgr.Loop);
            ListSecond.TryAdd(ServerTimer.LoopSecond);
            ListSecond.TryAdd(LoopPlayer.LoopAllPlayerSecond);
            ListSecond.TryAdd(CombatMgr.LoopSecond);

            //ListSecond3
            //ListSecond3.TryAdd(GameWebSocket.Loop);

            //ListSecond10
            ListSecond10.TryAdd(PubDataLoadMgr.获取负载列表游戏服务器);


            //ListMinute
            ListMinute.TryAdd(Util.RandomReset);
            ListMinute.TryAdd(ServerTimer.LoopMinute);
            ListMinute.TryAdd(NoticeMgr.LoopMinute);
            ListMinute.TryAdd(ServerMgrGame.LoadUpdate);
            ListMinute.TryAdd(() => { loger.Info($"服务器分钟更新"); });

            //ListMinute10
            ListMinute10.TryAdd(() => { loger.Warn($"服务器十分钟更新"); });


            //ListHour
            ListHour.TryAdd(() =>
            {
                if (BaseServerInfo.MysqlState)
                {
                    BaseServerInfo.DbMysqlMain.LoopExecute();
                }
            });
            ListHour.TryAdd(RoomMgr.RoomUpdate);
            ListHour.TryAdd(() => { loger.Warn($"服务器小时更新"); });



            //ListOClock
            ListOClock.TryAdd(() => { loger.Warn($"服务器整点更新"); });

            //ListOClock0
            ListOClock0.TryAdd(NoticeMgr.DayUpdateDayZeroOClock);
            ListOClock0.TryAdd(() => { loger.Warn($"服务器日零点更新"); });

            //ListOClock5
            ListOClock5.TryAdd(ServerMgrGame.ServerAutoSave);
            ListOClock5.TryAdd(() => { loger.Warn($"服务器日五点更新"); });

            //ListDayEnd
            ListDayEnd.TryAdd(() => { loger.Warn($"服务器每日结束更新"); });


            //ListSunday
            ListSunday.TryAdd(() => { loger.Warn($"服务器周日零点更新"); });

            //ListMonday
            ListMonday.TryAdd(() => { loger.Warn($"服务器周一零点更新"); });

            //ListMonth
            ListMonth.TryAdd(() => { loger.Warn($"服务器月零点更新"); });


        }
        #endregion

        #region 临时数据

        // 心跳处理完时间
        private static long TicksEnd = 0;

        // 心跳开始时间
        private static DateTime DtNow = DateTime.Now;
        private static long TicksCur = 0;

        // 心跳计时
        private static long TicksMillisecond = 0;
        private static long TicksSecond = 0;
        private static long TicksSecond3 = 0;
        private static long TicksSecond10 = 0;
        private static long TicksMinute = 0;
        private static long TicksMinute10 = 0;
        private static long TicksHour = 0;

        //注册列表
        public static List<Action> ListMillisecond = new List<Action>();
        public static List<Action> ListSecond = new List<Action>();
        public static List<Action> ListSecond3 = new List<Action>();
        public static List<Action> ListSecond10 = new List<Action>();

        public static List<Action> ListMinute = new List<Action>();
        public static List<Action> ListMinute10 = new List<Action>();

        public static List<Action> ListHour = new List<Action>();

        public static List<Action> ListOClock = new List<Action>();
        public static List<Action> ListOClock0 = new List<Action>();
        public static List<Action> ListOClock5 = new List<Action>();

        public static List<Action> ListDayEnd = new List<Action>();

        public static List<Action> ListSunday = new List<Action>();
        public static List<Action> ListMonday = new List<Action>();

        public static List<Action> ListMonth = new List<Action>();

        #endregion

        #region 公共部分

        /// <summary>
        /// 服务器心跳
        /// </summary>
        public static void Loop()
        {
            DtNow = DateTime.Now;
            TicksCur = DtNow.Ticks;

            //需要心跳循环的管理器
            //消息分发
            BaseDispatch.Loop();

            //100毫秒心跳
            if (TicksMillisecond < TicksCur)
            {
                foreach (var item in ListMillisecond) { item(); }
                TicksMillisecond = TicksCur + (TimeSpan.TicksPerMillisecond * 100);
            }

            bool 玩家心跳 = false;
            //秒心跳
            if (TicksSecond < TicksCur)
            {
                //10秒心跳
                if (TicksSecond10 < TicksCur)
                {
                    foreach (var item in ListSecond10) { item(); }
                    玩家心跳 = true;
                    TicksSecond10 = TicksCur + 10 * TimeSpan.TicksPerSecond;

                    //分钟心跳
                    if (TicksMinute < TicksCur)
                    {
                        foreach (var item in ListMinute) { item(); }
                        TicksMinute = TicksCur + TimeSpan.TicksPerMinute;
                    }
                    //10分钟心跳
                    if (TicksMinute10 < TicksCur)
                    {
                        foreach (var item in ListMinute10) { item(); }
                        TicksMinute10 = TicksCur + 10 * TimeSpan.TicksPerMinute;
                    }
                    //小时心跳
                    if (TicksHour < TicksCur)
                    {
                        foreach (var item in ListHour) { item(); }
                        TicksHour = TicksCur + TimeSpan.TicksPerHour;
                    }
                    //整点心跳
                    if (!DtNow.SameDayHour(GetBaseDatetime(EDataServerDtKey.日整点)))
                    {
                        foreach (var item in ListOClock) { item(); }
                        SetBaseDatetime(EDataServerDtKey.日整点, DtNow);
                    }
                    //日更新
                    if (!DtNow.SameDayHour(GetBaseDatetime(EDataServerDtKey.日更新)) && DtNow.Hour == 0)
                    {
                        foreach (var item in ListOClock0) { item(); }
                        SetBaseDatetime(EDataServerDtKey.日更新, DtNow);
                    }
                    //五点心跳
                    if (!DtNow.SameDayHour(GetBaseDatetime(EDataServerDtKey.日五点)) && DtNow.Hour == 5)
                    {
                        foreach (var item in ListOClock5) { item(); }
                        SetBaseDatetime(EDataServerDtKey.日五点, DtNow);
                    }
                    //日结束
                    if (!DtNow.SameDayHourMinute(GetBaseDatetime(EDataServerDtKey.日结束)) && DtNow.Hour == 23 && DtNow.Minute == 57)
                    {
                        foreach (var item in ListDayEnd) { item(); }
                        SetBaseDatetime(EDataServerDtKey.日结束, DtNow);
                    }
                    //周更新
                    if (!DtNow.SameWeek(GetBaseDatetime(EDataServerDtKey.周日零点更新), false))
                    {
                        foreach (var item in ListSunday) { item(); }
                        SetBaseDatetime(EDataServerDtKey.周日零点更新, DtNow);
                    }
                    //周一更新
                    if (!DtNow.SameWeek(GetBaseDatetime(EDataServerDtKey.周一零点更新), true))
                    {
                        foreach (var item in ListMonday) { item(); }
                        SetBaseDatetime(EDataServerDtKey.周一零点更新, DtNow);
                    }
                    //月更新
                    if (!DtNow.SameMonth(GetBaseDatetime(EDataServerDtKey.月零点更新)))
                    {
                        foreach (var item in ListMonth) { item(); }
                        SetBaseDatetime(EDataServerDtKey.月零点更新, DtNow);
                    }
                }

                //3秒心跳
                if (TicksSecond3 < TicksCur)
                {
                    foreach (var item in ListSecond3) { item(); }
                    TicksSecond3 = TicksCur + 3 * TimeSpan.TicksPerSecond;
                }

                //秒心跳
                if (true)
                {
                    foreach (var item in ListSecond) { item(); }
                    TicksSecond = TicksCur + TimeSpan.TicksPerSecond;
                }
            }

            if (玩家心跳)
            {
                LoopPlayer.LoopAllPlayerSecond10();
            }

            TicksEnd = DateTime.Now.Ticks;

            //如果执行时间超过2秒 提示服务器超载或者是中途逻辑出错
            if (TicksEnd - TicksCur > 2 * TimeSpan.TicksPerSecond)
            {
                loger.Error($"__________等待时间累计超时，耗时:{(TicksEnd - TicksCur) / TimeSpan.TicksPerSecond}秒 连接数:{BaseAppServer.SessionCount} 处理消息数:{BaseDispatch.CountMsgs} (可能是服务器过载 也可能是服务器内部出错)__________");
            }
        }

        #endregion

        #region Dump
        public static void Dump()
        {
            Dump(ListMillisecond);
            Dump(ListSecond);
            Dump(ListSecond3);
            Dump(ListSecond10);
            Dump(ListMinute);
            Dump(ListMinute10);
            Dump(ListHour);
            Dump(ListOClock);
            Dump(ListOClock0);
            Dump(ListOClock5);
            Dump(ListDayEnd);
            Dump(ListSunday);
            Dump(ListMonday);
            Dump(ListMonth);
        }
        public static void Dump(List<Action> list)
        {
            foreach (var item in list)
            {
                loger.Debug($"{item.Method} {item.Method}");
            }
        } 
        #endregion

    }
}